package xyz.scootaloo.kami.server.service.impl

import xyz.scootaloo.kami.server.model.SysFile
import xyz.scootaloo.kami.server.model.SysLog
import xyz.scootaloo.kami.server.model.dao.FileDAO
import xyz.scootaloo.kami.server.model.dao.LogDAO
import xyz.scootaloo.kami.server.standard.toJsonObject
import xyz.scootaloo.kami.server.service.*
import xyz.scootaloo.kami.server.service.FileLogService.*
import xyz.scootaloo.kami.server.service.broadcast.createDirCapChangeEvent
import xyz.scootaloo.kami.server.service.broadcast.createFileAddEvent
import xyz.scootaloo.kami.server.service.broadcast.createFileDeleteEvent
import xyz.scootaloo.kami.server.service.broadcast.createFileRenameEvent

/**
 * @author flutterdash@qq.com
 * @since 2022/3/11 17:44
 */
object InternalFileLogServiceImpl : FileLogService, ApplicationStageListener {

    private const val logType = "file"

    private val fileResolver = FileResolver()
    private val broadcastService = BroadcastService()

    override fun afterApplicationStarted() {
    }

    override fun onFileUpload(operator: Int, basePath: String, filename: String) {
        onFileCreate(operator, basePath, filename)
    }

    override fun onFileRename(operator: Int, basePath: String, oldName: String, newName: String) {
        val oldFilepath = buildFilepath(basePath, oldName)
        val newFilepath = buildFilepath(basePath, newName)
        Async.run { FileDAO.move(oldFilepath, newFilepath) }
        Async.run { LogDAO.store(createFileLogObj(operator, FileRenameLog(oldFilepath, newFilepath))) }
        Async.run { broadcastService.publish(createFileRenameEvent(basePath, oldName, newName)) }
    }

    override fun onFileCreate(operator: Int, basePath: String, filename: String) {
        val filepath = buildFilepath(basePath, filename)
        Async.run { FileDAO.store(SysFile.create(operator, filepath)) }
        Async.run { LogDAO.store(createFileLogObj(operator, FileCreateLog(filepath))) }
        publishFileAddEvent(basePath, filename)
    }

    override fun onFileDelete(operator: Int, basePath: String, filename: String) {
        val fullFilepath = buildFilepath(basePath, filename)
        Async.run { FileDAO.delete(fullFilepath) }
        Async.run { LogDAO.store(createFileLogObj(operator, FileDeleteLog(fullFilepath))) }
        Async.run { broadcastService.publish(createFileDeleteEvent(basePath, filename)) }
    }

    override fun onFileMove(operator: Int, oldFilepath: String, filename: String, newFilepath: String) {
        val oldFullFilepath = fileResolver.buildFilepath(oldFilepath, filename)
        val newFullFilepath = fileResolver.buildFilepath(newFilepath, filename)
        Async.run { FileDAO.move(oldFullFilepath, newFullFilepath) }
        Async.run { LogDAO.store(createFileLogObj(operator, FileMoveLog(oldFullFilepath, newFullFilepath))) }
        publishFileAddEvent(newFilepath, filename)
    }

    override fun onFileModify(operator: Int, basePath: String, filename: String) {
    }

    override fun onDirectoryCreate(operator: Int, basePath: String, dirname: String) {
        onFileCreate(operator, basePath, dirname)
    }

    override fun onDirectoryDelete(operator: Int, filepath: String) {
        val (basePath, filename) = fileResolver.splitFilepath(filepath)
        onFileDelete(operator, basePath, filename)
    }

    override fun onCapacityChange(dirPath: String, limit: Long, free: Long) {
        Async.run {
            val event = createDirCapChangeEvent(dirPath, limit, free)
            broadcastService.publish(event)
        }
    }

    private fun publishFileAddEvent(basePath: String, filename: String) = Async.run {
        val filepath = fileResolver.buildFilepath(basePath, filename)
        val event = createFileAddEvent(basePath, filename, fileResolver.resolveFile(filepath))
        broadcastService.publish(event)
    }

    private fun createFileLogObj(operator: Int, log: FileLog): SysLog {
        return SysLog.create(operator, log.subject, logType, log.json())
    }

    private fun FileLog.json(): String {
        return toJsonObject().toString()
    }

    private fun buildFilepath(basePath: String, vararg appends: String): String {
        return fileResolver.buildFilepath(basePath, *appends)
    }
}